package com.emperor.inventory.app;

import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.apache.log4j.Logger;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.MouseAdapter;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.ShellAdapter;
import org.eclipse.swt.events.ShellEvent;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;

import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.MenuItem;
import org.eclipse.swt.widgets.MessageBox;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.swt.widgets.Text;
import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.criterion.Expression;
import org.hibernate.criterion.Restrictions;

import com.emperor.cashier.app.CashierAppCtrl;
import com.emperor.category.app.CategoryAppCtrl;
import com.emperor.category.logic.Category;
import com.emperor.category.logic.CategoryModel;
import com.emperor.core.app.App;
import com.emperor.core.app.AppBase;
import com.emperor.core.app.AppConstant;
import com.emperor.product.app.ProductAppCtrl;
import com.emperor.product.app.ProductAppNew;
import com.emperor.product.logic.Product;
import com.emperor.product.logic.ProductModel;
import com.emperor.productlog.logic.ProductLog;
import com.emperor.transaction.logic.Transaction;
import com.emperor.transaction.logic.TransactionModel;
import com.emperor.treatment.logic.Treatment;
import com.emperor.util.HibernateUtil;
import com.swtdesigner.SWTResourceManager;

public class InventoryAppEnq extends AppBase implements App {

	private Text txtSKU;
	protected Shell shell;
	public static Logger log = Logger.getLogger(InventoryAppEnq.class);
	private NumberFormat nf0, nf2;

	public InventoryAppEnq() {
		super();
	}

	public InventoryAppEnq(Map<String, Object> params) {
		super();
		this.params = params;
	}

	/**
	 * Launch the application
	 * 
	 * @param args
	 */
	public static void main(String[] args) {
		try {
			InventoryAppEnq window = new InventoryAppEnq();
			window.open();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * Open the window
	 */
	public void open() {
		final Display display = Display.getDefault();
		createContents();
		shell.open();
		shell.layout();
		while (!shell.isDisposed()) {
			if (!display.readAndDispatch())
				display.sleep();
		}
	}

	/**
	 * Create contents of the window
	 */
	protected void createContents() {
		shell = new Shell();
		shell.setBackgroundImage(SWTResourceManager.getImage(
				InventoryAppEnq.class, "/img/main.jpg"));
		shell.setBackgroundMode(SWT.INHERIT_DEFAULT);
		shell.setImage(SWTResourceManager.getImage(InventoryAppEnq.class,
				"/img/iMac OSX.png"));
		shell.setFont(SWTResourceManager.getFont("", 12, SWT.NONE));
		shell.setSize(1280, 800);
		shell.setText("Search Inventory");

		initScreen(shell, getParams());
		nf0 = NumberFormat.getInstance();
		nf0.setMaximumFractionDigits(0);
		nf0.setMinimumFractionDigits(0);
		nf2 = NumberFormat.getInstance();
		nf2.setMaximumFractionDigits(2);
		nf2.setMinimumFractionDigits(2);

		final Composite composite = new Composite(shell, SWT.NONE);
		composite.setBounds(0, 50, 992, 500);

		final Label messageLabel = new Label(composite, SWT.NONE);
		messageLabel.setFont(org.eclipse.wb.swt.SWTResourceManager.getFont(
				"Segoe UI", 12, SWT.NORMAL));
		messageLabel.setBounds(10, 0, 872, 20);
		messageLabel
				.setText("Please select the product category and enter a product name to search.");

		final Table table = new Table(composite, SWT.FULL_SELECTION
				| SWT.BORDER);
		table.addMouseListener(new MouseAdapter() {
			public void mouseDoubleClick(final MouseEvent e) {
				doUpdateProduct(table);
			}
		});
		table.setFont(org.eclipse.wb.swt.SWTResourceManager.getFont("Segoe UI",
				12, SWT.NORMAL));
		table.setLocation(10, 137);
		table.setSize(972, 349);
		table.setLinesVisible(true);
		table.setHeaderVisible(true);

		final TableColumn newColumnTableColumn = new TableColumn(table,
				SWT.NONE);
		newColumnTableColumn.setWidth(54);
		newColumnTableColumn.setText("No.");

		final TableColumn newColumnTableColumn_1 = new TableColumn(table,
				SWT.NONE);
		newColumnTableColumn_1.setWidth(162);
		newColumnTableColumn_1.setText("SKU");

		final TableColumn newColumnTableColumn_2 = new TableColumn(table,
				SWT.NONE);
		newColumnTableColumn_2.setWidth(385);
		newColumnTableColumn_2.setText("Item");

		final TableColumn newColumnTableColumn_3 = new TableColumn(table,
				SWT.NONE);
		newColumnTableColumn_3.setWidth(129);
		newColumnTableColumn_3.setText("U/Price");

		final TableColumn newColumnTableColumn_4 = new TableColumn(table,
				SWT.NONE);
		newColumnTableColumn_4.setWidth(94);
		newColumnTableColumn_4.setText("Quantity");
		populateMessage(messageLabel);

		final Label productCategoryLabel = new Label(composite, SWT.NONE);
		productCategoryLabel.setFont(org.eclipse.wb.swt.SWTResourceManager
				.getFont("Segoe UI", 12, SWT.NORMAL));
		productCategoryLabel.setText("Product Category");
		productCategoryLabel.setBounds(10, 29, 125, 20);

		final Combo combo = new Combo(composite, SWT.READ_ONLY);
		combo.setFont(org.eclipse.wb.swt.SWTResourceManager.getFont("Segoe UI",
				12, SWT.NORMAL));
		combo.setBounds(141, 26, 408, 28);

		final Text text = new Text(composite, SWT.BORDER);
		text.setFont(org.eclipse.wb.swt.SWTResourceManager.getFont("Segoe UI",
				12, SWT.NORMAL));
		text.setBounds(141, 65, 408, 30);

		final Button searchButton = new Button(composite, SWT.NONE);
		searchButton.setImage(SWTResourceManager.getImage(
				InventoryAppEnq.class, "/img/Zoom-in.png"));
		searchButton.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(final SelectionEvent e) {
				populateTable(table, text, txtSKU, combo, messageLabel);
			}
		});
		searchButton.setFont(org.eclipse.wb.swt.SWTResourceManager.getFont(
				"Segoe UI", 12, SWT.NORMAL));
		searchButton.setText("Search");
		searchButton.setBounds(572, 99, 90, 30);

		//
		buildStandardMenu(getShell(), getParams(), CashierAppCtrl.CASHIER_CTRL,
				CashierAppCtrl.CASHIER_FORM);
		populateCombo(combo);
		populateTable(table, text, txtSKU, combo, messageLabel);

		final Label productNameLabel = new Label(composite, SWT.NONE);
		productNameLabel.setFont(org.eclipse.wb.swt.SWTResourceManager.getFont(
				"Segoe UI", 12, SWT.NORMAL));
		productNameLabel.setText("Product Name");
		productNameLabel.setBounds(10, 68, 105, 20);

		txtSKU = new Text(composite, SWT.BORDER);
		txtSKU.setBounds(141, 101, 408, 30);
		txtSKU.setFont(org.eclipse.wb.swt.SWTResourceManager.getFont(
				"Segoe UI", 12, SWT.NORMAL));

		final Label productNameLabel_1 = new Label(composite, SWT.NONE);
		productNameLabel_1.setBounds(10, 104, 105, 20);
		productNameLabel_1.setFont(org.eclipse.wb.swt.SWTResourceManager
				.getFont("Segoe UI", 12, SWT.NORMAL));
		productNameLabel_1.setText("SKU");

		final Group productGroup = new Group(shell, SWT.NONE);
		productGroup.setText("Product");
		productGroup.setFont(org.eclipse.wb.swt.SWTResourceManager.getFont(
				"Segoe UI", 12, SWT.NORMAL));
		productGroup.setBounds(10, 556, 295, 59);

		final Button addNewProductButton = new Button(productGroup, SWT.NONE);
		addNewProductButton.setBounds(10, 19, 65, 30);
		addNewProductButton.setImage(SWTResourceManager.getImage(
				InventoryAppEnq.class, "/img/Symbol-Add.png"));
		addNewProductButton.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(final SelectionEvent e) {
				doNewProduct();
			}
		});
		addNewProductButton.setFont(org.eclipse.wb.swt.SWTResourceManager
				.getFont("Segoe UI", 12, SWT.NORMAL));
		addNewProductButton.setText("Add");

		final Button updateProductButton = new Button(productGroup, SWT.NONE);
		updateProductButton.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(final SelectionEvent e) {
				doUpdateProduct(table);
			}
		});
		updateProductButton.setBounds(81, 19, 90, 30);
		updateProductButton.setImage(SWTResourceManager.getImage(
				InventoryAppEnq.class, "/img/Edit.png"));
		updateProductButton.setFont(org.eclipse.wb.swt.SWTResourceManager
				.getFont("Segoe UI", 12, SWT.NORMAL));
		updateProductButton.setText("Update");

		final Button deleteProductButton = new Button(productGroup, SWT.NONE);
		deleteProductButton.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(final SelectionEvent e) {
				if (!isProductInTransaction(table)) {
					int rowCount = doDeleteProduct(table);
					if (rowCount == 1) {
						populateTable(table, text, txtSKU, combo, messageLabel);
					}
				} else {
					message(getShell(),
							"Delete Error.",
							"Unable to delete product. Product already used in transaction.",
							SWT.ICON_ERROR | SWT.OK);
				}
			}
		});
		deleteProductButton.setBounds(177, 19, 85, 30);
		deleteProductButton.setImage(SWTResourceManager.getImage(
				InventoryAppEnq.class, "/img/Symbol-Delete.png"));
		deleteProductButton.setFont(org.eclipse.wb.swt.SWTResourceManager
				.getFont("Segoe UI", 12, SWT.NORMAL));
		deleteProductButton.setText("Delete");

		final Group categoryGroup = new Group(shell, SWT.NONE);
		categoryGroup.setText("Category");
		categoryGroup.setFont(org.eclipse.wb.swt.SWTResourceManager.getFont(
				"Segoe UI", 12, SWT.NORMAL));
		categoryGroup.setBounds(447, 556, 406, 59);

		final Button addNewCategoryButton = new Button(categoryGroup, SWT.NONE);
		addNewCategoryButton.setBounds(10, 20, 65, 30);
		addNewCategoryButton.setImage(SWTResourceManager.getImage(
				InventoryAppEnq.class, "/img/Symbol-Add.png"));
		addNewCategoryButton.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(final SelectionEvent e) {
				doNewCategory();
			}
		});
		addNewCategoryButton.setFont(org.eclipse.wb.swt.SWTResourceManager
				.getFont("Segoe UI", 12, SWT.NORMAL));
		addNewCategoryButton.setText("Add");

		final Button addNewProductButton_2 = new Button(categoryGroup, SWT.NONE);
		addNewProductButton_2.setBounds(81, 20, 90, 30);
		addNewProductButton_2.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(final SelectionEvent e) {
				doUpdateCategory(combo);
			}
		});
		addNewProductButton_2.setImage(SWTResourceManager.getImage(
				InventoryAppEnq.class, "/img/Edit.png"));
		addNewProductButton_2.setFont(org.eclipse.wb.swt.SWTResourceManager
				.getFont("Segoe UI", 12, SWT.NORMAL));
		addNewProductButton_2.setText("Update");

		final Button addNewProductButton_3 = new Button(categoryGroup, SWT.NONE);
		addNewProductButton_3.setVisible(false);
		addNewProductButton_3.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(final SelectionEvent e) {
				doDeleteCategory(combo);
			}
		});
		addNewProductButton_3.setBounds(177, 20, 85, 30);
		addNewProductButton_3.setImage(SWTResourceManager.getImage(
				InventoryAppEnq.class, "/img/Symbol-Delete.png"));
		addNewProductButton_3.setFont(SWTResourceManager.getFont("", 12,
				SWT.NONE));
		addNewProductButton_3.setText("Delete");

	}

	private void populateTable(Table table, Text text, Text txtSKU,
			Combo combo, Label label) {
		table.removeAll();
		table.clearAll();
		table.redraw();
		try {
			Session session = HibernateUtil.getSessionFactory()
					.getCurrentSession();
			session.beginTransaction();

			List<Product> products = new ArrayList<Product>();
			Criteria cris = session.createCriteria(ProductModel.class);
			if (combo.getText() != null && combo.getText().length() > 0) { // populateTable
																			// by
																			// category
				List<Category> categories = session
						.createCriteria(CategoryModel.class)
						.add(Expression.eq(Category.FLD_NAME, combo.getText()))
						.add(Expression.eq(Category.FLD_STATUS,
								AppConstant.STATUS_ACTIVE)).list();
				Category category = new CategoryModel();
				if (categories != null && !categories.isEmpty()) {
					category = categories.get(0);
					cris.add(Expression.eq(Product.FLD_CATEGORY, category));
				}
			}

			cris.add(Expression.eq(Product.FLD_STATUS,
					AppConstant.STATUS_ACTIVE));

			if (text.getText() != null && text.getText().length() > 0) {
				cris.add(Expression.like(Product.FLD_NAME, "%" + text.getText()
						+ "%"));
			}
			if (txtSKU.getText() != null && txtSKU.getText().length() > 0) {
				cris.add(Expression.like(Product.FLD_SKU,
						"%" + txtSKU.getText() + "%"));
			}

			products = cris.list();

			if (products != null && !products.isEmpty()) {
				int count = 0;
				for (Iterator<Product> iter = products.iterator(); iter
						.hasNext();) {
					Product product = iter.next();
					count++;
					TableItem item = new TableItem(table, SWT.BORDER);
					item.setText(new String[] { count + ".", product.getSku(),
							product.getName(), nf2.format(product.getPrice()),
							nf0.format(product.getQuantity()), });
					item.setData(product);
				}
			}
		} catch (Exception e) {
			log.error(e.getMessage(), e);
		}
	}

	private void populateCombo(Combo combo) {
		try {
			Session session = HibernateUtil.getSessionFactory()
					.getCurrentSession();
			session.beginTransaction();
			List<Category> categories = session
					.createCriteria(CategoryModel.class)
					.add(Restrictions.eq(Category.FLD_TYPE,
							Category.TYPE_PRODUCT))
					.add(Restrictions.eq(Category.FLD_STATUS,
							AppConstant.STATUS_ACTIVE)).list();
			if (categories != null && !categories.isEmpty()) {
				for (Iterator<Category> iter = categories.iterator(); iter
						.hasNext();) {
					Category category = iter.next();
					combo.add(category.getName());
					combo.setData(category.getName(), category);
				}
			}
		} catch (Exception e) {
			log.error(e.getMessage(), e);
		}
	}

	private void doUpdateCategory(Combo combo) {
		try {
			if (combo.getText() != null && combo.getText().length() > 0) {
				Session session = HibernateUtil.getSessionFactory()
						.getCurrentSession();
				session.beginTransaction();

				List<Category> categories = session
						.createCriteria(CategoryModel.class)
						.add(Expression.eq(Category.FLD_NAME, combo.getText()))
						.list();
				if (categories != null && !categories.isEmpty()) {
					Category category = categories.get(0);
					if (category != null && category.getId() != null) {
						getParams().put(CategoryAppCtrl.CATEGORY_ID,
								category.getId());

						getParams().put(AppConstant.APPCTRL,
								CategoryAppCtrl.CATEGORY_CTRL);
						getParams().put(AppConstant.ACTION,
								CategoryAppCtrl.CATEGORY_MGM);
						getParams().put(CategoryAppCtrl.CATEGORY_TYPE,
								Category.TYPE_PRODUCT);
						getShell().close();
					}
				}
			}
		} catch (Exception e) {
			log.error("Unable to update category.", e);
		}
	}

	private int doDeleteCategory(Combo combo) {
		int rowCount = 0;
		try {

		} catch (Exception e) {
			log.error("Unable to delete category.", e);
		}
		return rowCount;
	}

	private void doUpdateProduct(Table table) {
		try {
			TableItem[] items = table.getSelection();
			if (items != null && items.length > 0) {
				for (int i = 0; i < items.length; i++) {
					TableItem item = items[i];
					if (item.getData() != null) {
						Product product = (Product) item.getData();
						getParams().put(ProductAppCtrl.PRODUCT_ID,
								product.getId());

						getParams().put(AppConstant.APPCTRL,
								ProductAppCtrl.PRODUCT_CTRL);
						getParams().put(AppConstant.ACTION,
								ProductAppCtrl.PRODUCT_MGM);
						getShell().close();
					}
				}
			}
		} catch (Exception e) {
			log.error("Unable to update product.", e);
		}
	}

	private int doDeleteProduct(Table table) {
		int rowCount = 0;
		try {
			TableItem[] items = table.getSelection();
			if (items != null && items.length > 0) {
				for (int i = 0; i < items.length; i++) {
					TableItem item = items[i];
					if (item.getData() != null) {
						Product product = (Product) item.getData();

						MessageBox box = new MessageBox(getShell(),
								SWT.ICON_QUESTION | SWT.OK | SWT.CANCEL);
						box.setText("Confirm Delete Product?");
						box.setMessage("Are you sure you want to delete this product?");

						int reply = box.open();
						if (reply == SWT.OK) {
							Session session = HibernateUtil.getSessionFactory()
									.getCurrentSession();

							try {
								session.beginTransaction();

								product.setStatus(AppConstant.STATUS_OBSOLETE);
								product = (Product) preUpdate(product,
										getParams());

								session.update(product);
								rowCount++;

								ProductAppNew.logProduct(product, getParams(),
										ProductLog.ACT_STOCK_OUT + "-"
												+ ProductLog.ACT_DELETE, null,
										product.getQuantity());

								session.getTransaction().commit();
							} catch (Exception ex) {
								session.getTransaction().rollback();
								throw ex;
							}
						}
						break;
					}
				}
			}
		} catch (Exception e) {
			log.error("Unable to delete product.", e);
		}
		return rowCount;
	}

	public static boolean isProductInTransaction(Table table) {
		boolean isFound = false;
		try {
			TableItem[] items = table.getSelection();
			if (items != null && items.length > 0) {
				for (int i = 0; i < items.length; i++) {
					Product product = (Product) items[i].getData();
					if (product != null && product.getId() != null) {
						Session session = HibernateUtil.getSessionFactory()
								.getCurrentSession();
						session.beginTransaction();
						List<Transaction> transactions = session
								.createCriteria(TransactionModel.class)
								.add(Expression.eq(Transaction.FLD_PRODUCT,
										product)).setMaxResults(1).list();
						if (transactions != null && !transactions.isEmpty()) {
							isFound = true;
							break;
						}
					}
				}
			}
		} catch (Exception e) {
			log.error("Unable to find in receipt.", e);
		}
		return isFound;
	}
	
	public static boolean isTreatmentInTransaction(Table table) {
		boolean isFound = false;
		try {
			TableItem[] items = table.getSelection();
			if (items != null && items.length > 0) {
				for (int i = 0; i < items.length; i++) {
					Treatment treatment = (Treatment) items[i].getData();
					if (treatment != null && treatment.getId() != null) {
						Session session = HibernateUtil.getSessionFactory()
								.getCurrentSession();
						session.beginTransaction();
						List<Transaction> transactions = session
								.createCriteria(TransactionModel.class)
								.add(Expression.eq(Transaction.FLD_TREATMENT,
										treatment)).setMaxResults(1).list();
						if (transactions != null && !transactions.isEmpty()) {
							isFound = true;
							break;
						}
					}
				}
			}
		} catch (Exception e) {
			log.error("Unable to find in receipt.", e);
		}
		return isFound;
	}

	private void doNewCategory() {
		getParams().put(AppConstant.APPCTRL, CategoryAppCtrl.CATEGORY_CTRL);
		getParams().put(AppConstant.ACTION, CategoryAppCtrl.CATEGORY_NEW);
		getParams().put(CategoryAppCtrl.CATEGORY_TYPE, Category.TYPE_PRODUCT);
		getShell().close();
	}

	private void doNewProduct() {
		getParams().put(AppConstant.APPCTRL, ProductAppCtrl.PRODUCT_CTRL);
		getParams().put(AppConstant.ACTION, ProductAppCtrl.PRODUCT_NEW);
		getShell().close();
	}

	private void populateMessage(Label label) {
		if (getParams().get(CategoryAppCtrl.CATEGORY_MSG) != null) {
			label.setText(getParams().get(CategoryAppCtrl.CATEGORY_MSG)
					.toString());
		}
	}

	public Shell getShell() {
		return shell;
	}

	public void setShell(Shell shell) {
		this.shell = shell;
	}

}
